﻿#include "ThreadCache.h"
#include "CentralCache.h"
#include "PageCache.h"


void* ThreadCache::Allocate(size_t size) {


	//计算需要多大的块
	size_t alignSize = SizeClass::RoundUp(size);
	//计算自由链表的桶下标
	size_t index = SizeClass::Index(size);
	//如果不为空直接从自由链表的头拿一块
	if (!_freeLists[index].Empty()) {
		return _freeLists[index].Pop();
	}
	else {
		//从CentralCache拿内容
		return FetchFromCentralCache(index, alignSize);
	}
}

void ThreadCache::Deallocate(void* ptr, size_t size) {

	assert(ptr);

	
		//找到对应的自由链表桶插入
		size_t index = SizeClass::Index(size);
		_freeLists[index].Push(ptr);
		if (_freeLists[index].Size() >= _freeLists[index].MaxSize()) {
			ListTooLong(&_freeLists[index], size);
		}

	

}

void* ThreadCache::FetchFromCentralCache(size_t index, size_t size) {
	
	//慢启动算法
	//计算一次从CentralCache的span里面的freelist拿多少个块
#if defined(_WIN64) || defined(_WIN32) 
	size_t batchNum = min(SizeClass::NumMoveSize(size), _freeLists[index].MaxSize());
#elif defined(__unix__)
	size_t batchNum = std::min(SizeClass::NumMoveSize(size), _freeLists[index].MaxSize());
#endif
	if (batchNum == _freeLists[index].MaxSize()) {
		_freeLists[index].MaxSize() += 1;
	}

	//拿到内存的起始地址和结束地址
	void* start = nullptr;
	void* end = nullptr;

	//实际拿到的块数
	size_t actualNum = CentralCache::GetInstance().FetchRangeObj(
		start, end, batchNum, size);
	assert(actualNum > 0);
	if (actualNum == 1) {
		return start;
	}
	//如果大于一块将其余的挂在对应的自由链表下
	else if (actualNum > 1) {
		_freeLists[index].PushRange(NextObj(start), end, actualNum - 1);
		return start;
	}
	else {
		assert(false);
		return nullptr;
	}

}


void ThreadCache::ListTooLong(FreeList* list, size_t size) {
	
	void* start = nullptr;
	void* end = nullptr;
	list->PopRange(start, end, list->MaxSize());
	CentralCache::GetInstance().ReleaseLisToSpans(start, size);


}